package de.bazinga.rotw.weapon;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import com.jme.input.MouseInput;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.scene.Node;
import com.jme.scene.state.CullState;
import com.jme.scene.state.ZBufferState;
import com.jmex.audio.AudioTrack;
import com.jmex.game.state.GameStateManager;

import de.bazinga.rotw.game.Game;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.model.ModelCache;
import de.bazinga.rotw.network.BasicSyncManager;
import de.bazinga.rotw.network.Client;
import de.bazinga.rotw.network.Server;
import de.bazinga.rotw.network.message.NewBulletMessage;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sound.Sound;

public class Uzi extends Weapon {	
	
	public static final int TOPTHIRD_DAMAGE = 10;
	public static final int MIDDLETHIRD_DAMAGE = 5;
	public static final int BOTTOMTHIRD_DAMAGE = 2;
	
	private int ammo = 0;
	protected long lastShoot = 0;
	private int magazines = 0;
	
	protected static Node weaponModel = null;
	
	private boolean isZoom = false;
	
	public Uzi() {
		this.ammo = 30;
	}
	
	
	public void updateWeapon(Player player) {
		// Fire?
		
		if(MouseInput.get().isButtonDown(0)) {
			BasicSyncManager syncManager = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getSyncManager();
			
			NewBulletMessage newBulletMessage = new NewBulletMessage();
			newBulletMessage.setWeaponFlag(NewBulletMessage.UZI);
			newBulletMessage.setLocation(player.getCameraPosition().clone());
			newBulletMessage.setDirection(Game.getGame().getCamera().getDirection().clone());
			newBulletMessage.setBulletColor(player.getBulletColor());
			
			
			if(canFire()) {
				if(syncManager instanceof Server) {
					// Tell the Clients to play Sound!
					((Server)syncManager).getServer().sendToAll(newBulletMessage);
					
					// Just Fire the bullet
					fireBullet(player,player.getCameraPosition().clone(), Game.getGame().getCamera().getDirection().clone(), false);
					player.fired();
				}else if(syncManager instanceof Client) {
					((Client) syncManager).getClient().sendToServer(newBulletMessage);
					player.fired();
				}
			}
		}
		


		/**
		 * Zoom
		 */
		if(MouseInput.get().isButtonDown(1)) {
			if(!isZoom) {
				Camera cam = Game.getGame().getCamera();
				cam.setFrustumNear(cam.getFrustumNear()+.7f);
				cam.update();
				cam.apply();
				isZoom = true;
			}
		}else{
			if(isZoom) {
				Camera cam = Game.getGame().getCamera();
				cam.setFrustumNear(cam.getFrustumNear()-.7f);
				cam.update();
				cam.apply();
				isZoom = false;
			}
		}
	}

	
	
	public void fireBullet(Person person, Vector3f location, Vector3f direction, boolean fromClient) {
		// Clean this up!!!
		Weapon.fireBullet(person, location, direction, NewBulletMessage.KNIFE, -1f, 
				Uzi.TOPTHIRD_DAMAGE, Uzi.MIDDLETHIRD_DAMAGE, Uzi.BOTTOMTHIRD_DAMAGE, 
				Uzi.TOPTHIRD_DAMAGE, Uzi.MIDDLETHIRD_DAMAGE, Uzi.BOTTOMTHIRD_DAMAGE, 
				8, true, true);
			
		
	}


	
	/**
	 * Can the player fire again?
	 * Checks if he can fire again and if he has enough Ammo (also subtracts ammo)
	 * @return
	 */
	public boolean canFire() {
		if((System.currentTimeMillis() - lastShoot) < 130 )
			return false;
		

		lastShoot = System.currentTimeMillis();
		
		if(ammo == 0) {
			if(Game.getGame().getSettings().isSFX()) {
				Sound.getInstance().getAudioTrack("sounds/uziEmpty.wav").play();
			}
			return false;
		}
		
		
		ammo--;
		
		return true;
	}
	
	
	
	
	public String getIcon() {
		return "uzi.png";
	}
	
	public Node getWeaponModel() {
		if(weaponModel == null) {
			initWeaponModel();
		}
		return weaponModel;
	}
	
	public static void initWeaponModel() {
		if(weaponModel == null) {
			weaponModel = new Node("weapon");
			
			
			// Load Model
			URL textureUrl = null;
			try {
				textureUrl = new File("weapons/").toURI().toURL();
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			Node weapon = ModelCache.getInstance().addModel(textureUrl, textureUrl, "/weapons/uzi.3ds");
			
			
	        weapon.setLocalScale(0.1f);
	        
	        
	        Quaternion rot = new Quaternion();
	        rot.fromAngleAxis(-90*FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
	        weapon.setLocalRotation(rot);
	        
	        
	        
	        Node rotNode = new Node("rot");
	        rotNode.setLocalTranslation(new Vector3f(-0.7f,-0.5f,2));
	        rotNode.attachChild(weapon);
	        
	        Quaternion rot1 = new Quaternion();
	        rot1.fromAngleAxis(180*FastMath.DEG_TO_RAD, Vector3f.UNIT_Y);
	        rotNode.setLocalRotation(rot1);
	        

	        ZBufferState zBuffer = Game.getGame().getDisplay().getRenderer().createZBufferState();
	        zBuffer.setEnabled(true);
	        zBuffer.setFunction(ZBufferState.TestFunction.Always);
	        rotNode.setRenderState(zBuffer);
	        
	        CullState culling = Game.getGame().getDisplay().getRenderer().createCullState();
	        culling.setEnabled(true);
	        culling.setCullFace(CullState.Face.Back);
	        rotNode.setRenderState(culling);
	        
	        weaponModel.attachChild(rotNode);
	        weaponModel.updateRenderState();
	        
		}
	}

	
	public void playerFired() {
		if(Game.getGame().getSettings().isSFX()) {
			Sound.getInstance().getAudioTrack("sounds/uzi.wav").play();
		}
	}
	

	/**
	 * Another player fired from the given Location
	 */
	public static void otherPlayerFired(Vector3f location) {
		Player player = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPlayer();
		
		if(Game.getGame().getSettings().isSFX() && player.getLocalTranslation().distance(location) < 50) {
			AudioTrack at = Sound.getInstance().getAudioTrack("sounds/shoot.wav");
			at.setWorldPosition(location);
			at.play();
		}
	}



	
	
	public boolean reload() {
		if(magazines > 0) {
			ammo = 30;
			magazines--;
			return true;
		}
		return false;
	}
	
	public int getMagazines() {
		return magazines;
	}
	
	public boolean canReload() {
		return true;
	}
	
	/**
	 * The time he need to return
	 * @return in ms
	 */
	public int getReloadLag() {
		return 2500;
	}
	
	
	public int getAmmo() {
		return ammo;
	}


	public void setAmmo(int ammo) {
		this.ammo = ammo;
	}


	public void refillAmmo() {
		if(magazines < 4) magazines++;
	}
	
	public float getSpeedFactor() {
		return 0.9f;
	}
	
}